from indentation import Language
space_width = 4

class C( Language ):
    # keywords which require indentation in C language.
    keywords = [ "if", "else", "switch", "for", "while", "do", "case", "default", "class", "public", "private" ]
    
    def __init__( self, filename ):
        super().__init__( filename )
    def indent( self, spaces = 0, case_stack = [] ):
        keyword_seen = False
        quote_seen = False
        consume = True
        while True:
            token, state = self.getToken()
            if state == Language.WORD:
                # write the token to buffer.
                self.push( token )
                
                # in this state, token can be a keyword, a function name or a variable.
                # if it is a keyword, set keyword_seen to True. wait until '{' char is seen then call
                # self.indentation() recursiverly with updated space value.
                if not quote_seen and token in C.keywords:
                    keyword_seen = True
                    if token == "case" or token == "default" or token == "private" or token == "public":
                        case_stack.append( token )
                        # if lexer has already seen cases, then adjust indentation.
                        if len( case_stack ) > 1:
                            # pop the current 'case' token.
                            self.pop()
                            # pop the spaces.
                            self.pop()
                            # restore 'case' token.
                            self.push( token )
                # see whether token is a function name.
                elif not quote_seen and self.peek( "(" ):
                    keyword_seen = True
                
            elif state == Language.NUMBER:
                self.push( token )
                
            elif state == Language.EMPTY:
                continue
                
            elif state == Language.SPECIAL_CHAR:
                # write the token to buffer.
                self.push( token )
                # if it is the begining of literal, then no need to cosume space.
                if token == '"':
                    # seeing quote for the first time.
                    if not quote_seen:
                        quote_seen = True
                        consume = False
                    else:
                        quote_seen = False
                        consume = True
                # if it is the '{' => begining of the block, 
                # update space variable, recursiverly call indent function,[ only if keyword_seen is set to true.]
                elif token == '{':
                    if keyword_seen:
                        self.indent( spaces  + 1 )
                        keyword_seen = False
                # begining of case block.
                elif token == ':':
                    if keyword_seen:
                        if len( case_stack ) == 1:
                            spaces += 1
                        self.indent( spaces, case_stack )
                        try:
                            case_stack.pop()
                            return
                        except IndexError:
                            pass                               
                elif token == '}':
                    # end of the block.
                    if case_stack:
                        count = 1
                        if len( case_stack ) > 1:
                            count = 2                        
                        for _ in range( 0, count ):
                            # removes '}'
                            self.pop()
                            # removes previously added spaces.
                            self.pop()
                            # restore '}'
                            self.push( token )
                    else:
                        # normal case.
                        # removes '}'
                        self.pop()
                        # removes previously added spaces.
                        self.pop()
                        # restore '}'
                        self.push( token )
                    return
            elif state == Language.SPACE:
                # check whether it is new line or not.
                # if new line, then push new line to buffer then push "' ' * spaces" into the buffer.
                if consume:
                    # preference is given to new line, as it is needed to create good indentation.
                    if '\n' in token:
                        self.push( '\n' )
                        for _ in range( spaces ):
                            self.push( ' ' * space_width )
                    else:
                        self.push( token[ 0 ] )
                else:
                    self.push( token )
                    
            elif state == Language.END:
                break

a = C( "test1.py" )
a.indent()
a.write()
